package com.dragon.blelibrary.manager;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;

import com.dragon.blelibrary.BleConfig;
import com.dragon.blelibrary.bleutils.BleLOG;
import com.dragon.blelibrary.bleutils.BluctoothUtil;
import com.dragon.blelibrary.events.BleEventType;
import com.dragon.blelibrary.events.BlePropertyObservable;
import com.dragon.blelibrary.lib.DispatchMessages;
import com.dragon.blelibrary.lib.GattCallbackOut;
import com.dragon.blelibrary.scandevise.BleDeviceScan;
import com.dragon.blelibrary.scandevise.IScanListener;

import java.util.HashMap;
import java.util.Set;
import java.util.UUID;

public class BleUtils {
    private String tag = "BleManager";
    //    private List<BluetoothDevice> mManagedDevices;
    private HashMap<BluetoothDevice, MyBleManager> mBleManagers;
    /**保存连接的配置参数*/
    private HashMap<BluetoothDevice,BleConnectParam> mConnectParams;
    private static BleUtils instance;
    private DispatchMessages dispatchMessages;
    //是否使能所有的通知（默认否）
    private boolean enableAllNotify = false;
    //ble接口事件外调
    private GattCallbackOut gattCallbackOut;
    private Handler mHandler;
    public static BleUtils getInstance(){
        if(instance == null){
            instance = new BleUtils();
        }
        return instance;
    }
    private BleUtils(){}
    public void onCreate(){
        // Initialize the map of BLE managers
        mBleManagers = new HashMap<>();
        mConnectParams = new HashMap<>();
        mHandler = new Handler(new HandlerCallback());
//        mManagedDevices = new ArrayList<>();
        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
//        filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);//指明一个与远程设备建立的低级别（ACL）连接。
//        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);//指明一个来自于远程设备的低级别（ACL）连接的断开
//        filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED);//指明一个为远程设备提出的低级别（ACL）的断开连接请求，并即将断开连接。
//        mContext.registerReceiver(mBluetoothStateBroadcastReceiver, filter);
        // Register broadcast receivers
        BleConfig.mContext.registerReceiver(mBluetoothStateBroadcastReceiver, filter);
        // Service has now been created
        onServiceCreated();

        // Call onBluetoothEnabled if Bluetooth enabled
        final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter.isEnabled()) {
            onBluetoothEnabled();
        }
    }

    /**
     * 预设消息处理回调
     * @param msg
     */
    public void setMessagesCallback(DispatchMessages msg){
        this.dispatchMessages = msg;
    }
    /**
     * 准备连接需要使能的通知
     * @param serviceNeme
     * @param serviceUUid
     * @param notifyName
     * @param notifyUUid
     */
    public void putNotificationMap(String serviceNeme, UUID serviceUUid, String notifyName, UUID notifyUUid){
        GattServiceCharacteristic.putNotificationMap(serviceNeme,serviceUUid,notifyName,notifyUUid);
    }
    /**
     * 给UUID名个名称方便打log
     * @param uuid
     * @param name
     */
    public void putUuidToName(UUID uuid,String name){
        GattServiceCharacteristic.putUuidToName(uuid,name);
    }

    /**
     * 清除uuid与需要使能的通知
     */
    public void clearNotify(){
        GattServiceCharacteristic.clearNotify();
    }
    /**
     * Called when the service has been created, before the {@link #onBluetoothEnabled()} is called.
     */
    protected void onServiceCreated() {
        // empty default implementation
    }

    /**
     * Returns an unmodifiable list of devices managed by the service.
     * The returned devices do not need to be connected at tha moment. Each of them was however created
     * using {@link #connect(BluetoothDevice)} method so they might have been connected before and disconnected.
     * @return unmodifiable list of devices managed by the service
     */
//    public final List<BluetoothDevice> getManagedDevices() {
//        return Collections.unmodifiableList(mManagedDevices);
//    }
    /**
     *  链接
     * @param connectParam
     */
    public void connect(BleConnectParam connectParam){
        if(connectParam != null && !TextUtils.isEmpty(connectParam.getAddress())){
            BluetoothDevice device = getDevice(connectParam.getAddress());
            connectParam.setDisConnectTimes(0);//断开次数归零
            if(connectParam.getReconnection() >= 0) {//如果是一直重连，那么超时失效
                long timeOut = connectParam.getTimeOut();
                long searchTime = connectParam.getReconnectSearchTime();
                sendTimeOut(connectParam.getAddress(),timeOut + searchTime);//开始倒计时，超时
            }
            if(mConnectParams.containsKey(device))
                mConnectParams.remove(device);
            mConnectParams.put(device,connectParam);//加入重连策略的队列
            if(!BluetoothAdapter.getDefaultAdapter().isEnabled()){//系统蓝牙未打开
                if(connectParam.isConnectOpenSysBle()){//连接时，系统蓝牙未打开的，是否打开系统蓝牙
                    BluetoothAdapter.getDefaultAdapter().enable();
                    return;//打开系统蓝牙后，这里暂时不连接，等待系统蓝牙打开后再去连接
                }
            }
            connect(device,connectParam.isBondIngDiscoverServices());
        }
    }
    /**
     *  链接
     * @param address
     */
    public void connect(String address){
        if(TextUtils.isEmpty(address))
            return;
        BluetoothDevice device = getDevice(address);
        connect(device,false);
    }

    /**
     * 链接
     * @param address
     * @param bondIngDiscoverServices 对于部分需要绑定的设备，在绑定中是否继续去发现服务(false：绑定中不发现，绑定完成后再去发现)
     */
    public void connect(String address,boolean bondIngDiscoverServices){
        if(TextUtils.isEmpty(address))
            return;
        BluetoothDevice device = getDevice(address);
        connect(device,bondIngDiscoverServices);
    }
    /**
     * Adds the given device to managed and stars connecting to it. If the device is already connected this method does nothing.
     * @param device target Bluetooth device
     */
    @SuppressWarnings("unchecked")
    public void connect(final BluetoothDevice device) {
        connect(device,false);
    }
    /**
     * Adds the given device to managed and stars connecting to it. If the device is already connected this method does nothing.
     * @param device target Bluetooth device
     *  @param bondIngDiscoverServices  对于部分需要绑定的设备，在绑定中是否继续去发现服务(false：绑定中不发现，绑定完成后再去发现)
     */

    @SuppressWarnings("unchecked")
    public void connect(final BluetoothDevice device,boolean bondIngDiscoverServices) {
        // If a device is in managed devices it means that it's already connected, or was connected
        // using autoConnect and the link was lost but Android is already trying to connect to it.
//        if (mManagedDevices.contains(device)){
//
//            return;
//        }
//
//        try {
//            mManagedDevices.add(device);
//        }catch (Exception e){
//
//        }
        if(mConnectParams != null && !mConnectParams.isEmpty())
            if(!mConnectParams.containsKey(device))
                return;
            else{
                BleConnectParam connectParam = mConnectParams.get(device);
                if(connectParam != null){
                    connectParam.setTimeOutDisconnect(false);//归零，是否是超时而断开的
                    BleLOG.i(tag,connectParam.toString());//打印一下连接配置参数的log
                }
            }
        MyBleManager manager = getBleManager(device);
        BleLOG.i(tag,"mBleManagers size = " + mBleManagers.size());
        if (manager != null) {
            manager.setBondIngDiscoverServices(bondIngDiscoverServices);
            manager.connect(device);
        } else {
            manager = new MyBleManager(BleConfig.mContext);
            manager.setBondIngDiscoverServices(bondIngDiscoverServices);
            mBleManagers.put(device, manager);
            manager.setGattCallbacks(callbacks);
            manager.connect(device);
        }
    }

    /**
     * 改变连接状态
     * @param address
     * @param connectType
     */
    public void changeConnectType(String address,BleConnectParam.ConnectType connectType){
        if(TextUtils.isEmpty(address))
            return;
        BluetoothDevice device = getDevice(address);
        if(!mConnectParams.isEmpty() && mConnectParams.containsKey(device)){
            mConnectParams.get(device).setConnectType(connectType);
        }
    }
    /**
     * 主动断开
     * @param address
     */
    public void disconnect(String address){
        if(TextUtils.isEmpty(address))
            return;
        BluetoothDevice device = getDevice(address);
        if(mConnectParams.containsKey(device)){
            mConnectParams.remove(device);//主动断开，则移除重连策略,不再重连了
            removeConnection(address);
            removeTimeOut( address);
            BleLOG.i(tag,"断开了重连策略 address = " + address);
        }
        disconnect(device);
    }

    /**
     * 移除重连策略，但不是断开
     * 用于主动断开前，而还要发送命令的，但又不需要重连的动作
     * 比如，移除设备，
     * @param address
     */
    public void removeReconnection(String address){
        if(TextUtils.isEmpty(address))
            return;
        BluetoothDevice device = getDevice(address);
        removeConnection(address);
        if(mConnectParams.containsKey(device)){
            mConnectParams.remove(device);//主动断开，则移除重连策略,不再重连了
        }
    }
    /**
     * 查询是否已经绑定
     * @param address
     * @return
     */
    public boolean isBanded(String address){
        BluetoothDevice device = getDevice(address);
        if(device == null)
            return false;
        return device.getBondState() == BluetoothDevice.BOND_BONDED;
    }
    /**
     * 是否已经发现了服务，
     * 后续使能通知，发送数据，前提是必须先发现服务，否则，会失败
     * @return
     */
    public boolean hasServices(String address){
        BluetoothDevice device = getDevice(address);
        if(device == null)
            return false;
        final MyBleManager manager = getBleManager(device);
        if(manager == null)
            return false;
        return manager.hasServices();
    }
    /**
     * Disconnects the given device and removes the associated BleManager object.
     * If the list of BleManagers is empty while the last activity unbinds from the service,
     * the service will stop itself.
     * @param device target device to disconnect and forget
     */
    public void disconnect(final BluetoothDevice device) {
        final MyBleManager manager = getBleManager(device);
        if (manager != null && manager.isConnected()) {
            manager.disconnect();
        }
        BleLOG.e(tag,"主动断开了---");
//        if(mManagedDevices.contains(device))
//            mManagedDevices.remove(device);
    }
    public boolean isConnected(String address){
        BluetoothDevice device = getDevice(address);
        return isConnected(device);
    }

    /**
     * 预设是否自动使能所有通知
     * @param enable
     */
    public void setEnableAllNotify(boolean enable){
        enableAllNotify = enable;

    }

    /**
     * 预设ble接口事件外调，一般用于第三方ota
     * @param callbackOut
     */
    public void setGattCallbackOut(GattCallbackOut callbackOut){
        gattCallbackOut = callbackOut;
    }

    /**
     * ble接口事件外调，一般用于第三方ota
     * @param address
     * @param callbackOut
     */
    public void setGattCallbackOut(String address,GattCallbackOut callbackOut){
        BluetoothDevice device = getDevice(address);
        if(device != null){
            MyBleManager manager = getBleManager(device);
            if(manager != null){
                manager.setGattCallbackOut(callbackOut);
            }
        }
    }
    /**
     * Returns <code>true</code> if the device is connected to the sensor.
     * @param device the target device
     * @return <code>true</code> if device is connected to the sensor, <code>false</code> otherwise
     */
    public final boolean isConnected(final BluetoothDevice device) {
        if(device == null)
            return false;
        final MyBleManager manager = getBleManager(device);
        return manager != null && manager.isConnected();
    }

    /**
     * 使能通知
     * @param address
     * @param serviceUUid
     * @param notifiUUID
     * @param isenable
     * @return
     */
    public boolean setEnableNotification(String address,UUID serviceUUid, UUID notifiUUID, boolean isenable){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if(manager != null){
            return manager.enableNotification(serviceUUid,notifiUUID,isenable);
        }
        return false;
    }

    /**
     * 请求mtu的大小，
     * @param address
     * @param mtu mtu大小值
     * @return
     */
    public boolean requestMtu(String address,int mtu){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if(manager != null){
            return manager.requestFendaMtu(mtu);
        }
        return false;

    }
    /**
     * Returns the connection state of given device.
     * @param device the target device
     * @return the connection state, as in {@link BleManager#getConnectionState()}.
     */
    public final int getConnectionState(final BluetoothDevice device) {
        final MyBleManager manager = getBleManager(device);
        return manager != null ? manager.getConnectionState() : BluetoothGatt.STATE_DISCONNECTED;
    }

    /**获取电量
     * Returns the last received battery level value.
     * @param address the device of which battery level should be returned
     * @return battery value or -1 if no value was received or Battery Level characteristic was not found
     */
    public int getBatteryValue(String address) {
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        return manager.getBatteryValue();
    }

    /**
     * 读取信号强度
     * @param address
     * @return
     */
    public boolean readRemoteRssi(String address){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if(manager != null){
            return manager.readRemoteRssi();
        }
        return false;
    }
    /*
        通过mac地址获取BluetoothDevice
     */
    private BluetoothDevice getDevice(String address){
        try {
            if (!TextUtils.isEmpty(address)){
                BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address);
                return device;
            }
            return null;
        }catch (IllegalArgumentException e){
            e.printStackTrace();
            return null;
        }

    }
    /*
    获取Manager
     */
    private MyBleManager getBleManager(BluetoothDevice device){
        return mBleManagers.get(device);
    }

    public void onDestroy(){
        onServiceStopped();
    }
    /**
     * Called when the service has been stopped.
     */
    protected void onServiceStopped() {
        // Unregister broadcast receivers
        BleConfig.mContext.unregisterReceiver(mBluetoothStateBroadcastReceiver);

        // The managers map may not be empty if the service was killed by the system
        for (final MyBleManager manager : mBleManagers.values()) {
            // Service is being destroyed, no need to disconnect manually.
            manager.close();
            manager.onDestroy();
//            manager.log(LogContract.Log.Level.INFO, "Service destroyed");
        }
        mBleManagers.clear();
//        mManagedDevices.clear();
        mBleManagers = null;
//        mManagedDevices = null;
    }
    private ManagerCallbacks callbacks = new ManagerCallbacks(){

        /**
         * 开始连接
         * @param device the device that got connected
         */
        @Override
        public void onDeviceConnecting(BluetoothDevice device) {
            BleLOG.i(tag,"onDeviceConnecting");
            MyBleManager manager = getBleManager(device);
            if(device != null && manager != null){
                if(dispatchMessages != null)
                    manager.setMessages(dispatchMessages);
                manager.setEnableAllNotify(enableAllNotify);
                if(gattCallbackOut != null)
                    manager.setGattCallbackOut(gattCallbackOut);
            }

        }


        /**
         * 连接成功
         * @param device the device that got connected
         */
        @Override
        public void onDeviceConnected(BluetoothDevice device) {
            removeTimeOut(device.getAddress());//移除倒计时
            BleConnectParam connectParam = null;
            if(mConnectParams.containsKey(device))
                connectParam = mConnectParams.get(device);
            BlePropertyObservable.getInstance().fireEvent(BleEventType.BLE_CONNECTED_NO_NOTIFY, device.getAddress(),connectParam);
            BleLOG.i(tag,"onDeviceConnected");
        }

        @Override
        public void onDeviceDisconnecting(BluetoothDevice device) {
            BleLOG.i(tag,"onDeviceDisconnecting");
        }

        /**
         * 连接断开了
         * @param device the device that got disconnected
         */
        @Override
        public void onDeviceDisconnected(BluetoothDevice device) {
            BleLOG.i(tag,"onDeviceDisconnected");

            // Note: if BleManager#shouldAutoConnect() for this device returned true, this callback will be
            // invoked ONLY when user requested disconnection (using Disconnect button). If the device
            // disconnects due to a link loss, the onLinklossOccur(BluetoothDevice) method will be called instead.

            // We no longer want to keep the device in the service
//            if(mManagedDevices.contains(device))
//                mManagedDevices.remove(device);
            // The BleManager is not removed from the HashMap in order to keep the device's log session.
            if(mBleManagers.containsKey(device)){
                MyBleManager manager = mBleManagers.remove(device);
                manager.close();
                manager.onDestroy();
                manager = null;
            }
            if(BluetoothAdapter.getDefaultAdapter().isEnabled()){//系统蓝牙未打开，表示是关系统蓝牙断开的，此时不重连
                if(!mConnectParams.isEmpty() && mConnectParams.containsKey(device)) {
                    BleConnectParam connectParam = mConnectParams.get(device);
                    connectParam.setSysBleIsEnabled(true);
                }
                reconnectParam(device);
            }else{
                if(!mConnectParams.isEmpty() && mConnectParams.containsKey(device)){
                    BleConnectParam connectParam = mConnectParams.get(device);
                    connectParam.setSysBleIsEnabled(false);
                    BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress(),connectParam);
                }else{
                    BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress());
                }
            }

        }

        @Override
        public void onLinklossOccur(BluetoothDevice device) {
            BleLOG.i(tag,"onLinklossOccur");
        }

        @Override
        public void onServicesDiscovered(BluetoothDevice device, boolean optionalServicesFound) {
            BleLOG.i(tag,"onServicesDiscovered");
        }

        @Override
        public void onDeviceReady(BluetoothDevice device) {
            BleLOG.i(tag,"onDeviceReady");
        }

        @Override
        public boolean shouldEnableBatteryLevelNotifications(BluetoothDevice device) {
            BleLOG.i(tag,"shouldEnableBatteryLevelNotifications");
            return true;
        }

        /**
         * 连接完成了
         * @param device
         */
        @Override
        public void onConnectionNotificationReturn(BluetoothDevice device) {
            BleLOG.i(tag,"通知已使能完毕");
            BleConnectParam connectParam = null;
            if(mConnectParams.containsKey(device)){
                connectParam = mConnectParams.get(device);
                connectParam.setConnceted(true);//标示已经连接成功过了
                connectParam.setDisConnectTimes(0);//断开次数归零
            }
            removeTimeOut(device.getAddress());//移除倒计时
            BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_CONNECTED, device.getAddress(),connectParam);
        }
        @Override
        public void onBatteryValueReceived(BluetoothDevice device, int value) {
//            BleLOG.i(tag,"onBatteryValueReceived");
            BlePropertyObservable.getInstance().fireEvent(BleEventType.BatteryValue, device.getAddress(),value);
        }

        @Override
        public void onBondingRequired(BluetoothDevice device) {
            BleLOG.i(tag,"onBondingRequired");
            BleConnectParam connectParam = null;
            if(mConnectParams.containsKey(device))
                connectParam = mConnectParams.get(device);
            BlePropertyObservable.getInstance().fireEvent(BleEventType.BLE_BONDING, device.getAddress(),connectParam);
        }

        @Override
        public void onBonded(BluetoothDevice device) {
            BleLOG.i(tag,"onBonded");
            BleConnectParam connectParam = null;
            if(mConnectParams.containsKey(device))
                connectParam = mConnectParams.get(device);
            BlePropertyObservable.getInstance().fireEvent(BleEventType.BLE_BONDED, device.getAddress(),connectParam);
        }

        /**
         * 出错了
         * @param device the device that caused an error
         * @param message
         *            the error message
         * @param errorCode
         *            the error code
         */
        @Override
        public void onError(BluetoothDevice device, String message, int errorCode) {
//            BleLOG.e(tag,"onError = "+message + " errorCode = " + errorCode);
            if(errorCode == 0 || errorCode == 19){//正常断开才移除超时
                removeTimeOut(device.getAddress());//移除倒计时
            }
            BleConnectParam connectParam = null;
            if(mConnectParams.containsKey(device))
                connectParam = mConnectParams.get(device);
            BlePropertyObservable.getInstance().fireEvent(BleEventType.BLE_ERROR, device.getAddress(),message,errorCode,connectParam);
        }

        @Override
        public void onDeviceNotSupported(BluetoothDevice device) {
            BleLOG.i(tag,"onDeviceNotSupported");
            // We don't like this device, remove it from both collections
//            if(mManagedDevices.contains(device))
//                mManagedDevices.remove(device);
            removeTimeOut(device.getAddress());//移除倒计时
            if(mBleManagers.containsKey(device)){
                MyBleManager manager = mBleManagers.remove(device);
                manager.close();
                manager.onDestroy();
            }
        }
    };
    private final BroadcastReceiver mBluetoothStateBroadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(intent.getAction())) {
                BleLOG.d(tag, "ACL---++----蓝牙已断开");
//                BlePropertyObservable.getInstance().fireEvent(BleEventType.ACL_DISCONNECTED, device.getAddress(),message,errorCode,connectParam);
            } else if (BluetoothDevice.ACTION_ACL_DISCONNECT_REQUESTED.equals(intent.getAction())) {
                BleLOG.d(tag, "ACL-----++------蓝牙即将断开");
            }else if (BluetoothDevice.ACTION_ACL_CONNECTED.equals(intent.getAction())) {
                BleLOG.d(tag, "ACL----++----建立了连接");
            }


            final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.STATE_OFF);
            final int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, BluetoothAdapter.STATE_OFF);

            switch (state) {
                case BluetoothAdapter.STATE_ON:
                    // On older phones (tested on Nexus 4 with Android 5.0.1) the Bluetooth requires some time
                    // after it has been enabled before some operations can start. Starting the GATT server here
                    // without a delay is very likely to cause a DeadObjectException from BluetoothManager#openGattServer(...).
                    BleConfig.mHandler.postDelayed(() -> onBluetoothEnabled(), 600);
                    break;
                case BluetoothAdapter.STATE_TURNING_OFF:
                case BluetoothAdapter.STATE_OFF:
                    if (previousState != BluetoothAdapter.STATE_TURNING_OFF && previousState != BluetoothAdapter.STATE_OFF)
                        onBluetoothDisabled();
                    break;
            }



        }
    };

    /**
     * This method is called when Bluetooth Adapter has been enabled. It is also called
     * after the service was created if Bluetooth Adapter was enabled at that moment.
     * This method could initialize all Bluetooth related features, for example open the GATT server.
     * Make sure you call <code>super.onBluetoothEnabled()</code> at this methods reconnects to
     * devices that were connected before the Bluetooth was turned off.
     * 蓝牙打开
     */
    protected void onBluetoothEnabled() {
//        for (final BluetoothDevice device : mManagedDevices) {
//            final MyBleManager manager = getBleManager(device);
//            if (!manager.isConnected())
//                manager.connect(device);
//        }
        if(mConnectParams != null && mConnectParams.size() > 0){
            Set<BluetoothDevice> keys = mConnectParams.keySet();
            for (BluetoothDevice device:keys) {
                //系统蓝牙打开后，倒计时重新开始
                BleConnectParam connectParam = mConnectParams.get(device);
                if(connectParam.isBleOpenConnect() || connectParam.isReopenSysBle() || connectParam.isConnectOpenSysBle()) {
                    if (connectParam.isTimeOutIncludeRestartSysBle()) {
                        //重新开始倒计时
                        long timeOut = connectParam.getTimeOut();
                        long searchTime = connectParam.getReconnectSearchTime();
                        sendTimeOut(connectParam.getAddress(),timeOut + searchTime);//开始倒计时，超时
                    }
                    reconnectParam(device);
                }
            }
        }
        BlePropertyObservable.getInstance().fireEvent(BleEventType.BLUETOOTH_ON, null);
    }
    /**
     * Method called when Bluetooth Adapter has been disabled.
     */
    protected void onBluetoothDisabled() {
        // do nothing, BleManagers have their own Bluetooth State broadcast received and will close themselves
        BlePropertyObservable.getInstance().fireEvent(BleEventType.BLUETOOTH_OFF, null);
    }

    /**
     * 重连机制
     */
    private synchronized void reconnectParam(BluetoothDevice device){
        if(mConnectParams.containsKey(device)){
            BleConnectParam connectParam = mConnectParams.get(device);
            connectParam.setDisConnectTimes(connectParam.getDisConnectTimes() + 1);
            int disConectTimes = connectParam.getDisConnectTimes();//断开次数
            int reconnection = connectParam.getReconnection();//重连次数
            if(connectParam != null){
                if(connectParam.isConnceted() //连接成功过了的
                        || connectParam.isTimeOutDisconnect()//超时断开的
                        || reconnection == disConectTimes //重连次数用完了的
                        || reconnection == 0)//不需要重连的
                {//符合以上条件的就不重连了，重连交给上层再调
//                    if(!connectParam.isAfterConnectedDisconnectUsedBefore()){//连接成功后，是否继续用之前的重连配置，
                    removeTimeOut(connectParam.getAddress());//移除超时
                    removeConnection(connectParam.getAddress());
                    BleLOG.e(tag,"断开，条件不符合，不再重连了 address = " + device.getAddress());
                    BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress(), connectParam);
                    return;//如果不用了，则不重连了
//                    }
                }
                if(connectParam.isTimeOutDisconnect()){//如果是超时断开的

                    return;
                }
                //断开了，
                BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress(), connectParam);
                if (reconnection != 0) {//需要重连
                    if (reconnection < 0 || reconnection > 3) {
                        //一直重连
                        //第3次，开始判断是否重开系统蓝牙
                        if (disConectTimes == 3 && connectParam.isReopenSysBle() && !connectParam.isReopenBleAction()) {
                            BluctoothUtil.trunOffOn(BleConfig.mContext, 1000);//一秒钟，重开蓝牙
//                            connectParam.setDisConnectTimes(connectParam.getDisConnectTimes() + 1);//断开次数加1
                            connectParam.setReopenBleAction(true);//标记已经重开过系统蓝牙了
                            if (connectParam.isTimeOutIncludeRestartSysBle()) {
                                removeTimeOut(device.getAddress());//移除倒计时
                            }
                        } else if(reconnection - disConectTimes >= 0){
                            //去重连
                            reconnectParamConnect(device, connectParam);
                        }
                    } else {
                        //重连多少次
                        //倒数第一，第二次判断是否重开系统蓝牙
                        if (disConectTimes - reconnection == -1) {//倒数第一次
                            if (!connectParam.isReopenBleAction() && connectParam.isReopenSysBle()) {
                                //如果小于3次重连的，就重开系统蓝牙
                                BluctoothUtil.trunOffOn(BleConfig.mContext, 1000);//一秒钟，重开蓝牙
                                connectParam.setReopenBleAction(true);//标记已经重开过系统蓝牙了
                                if (connectParam.isTimeOutIncludeRestartSysBle()) {
                                    removeTimeOut(device.getAddress());//移除倒计时
                                }
                            } else {
                                //如果大于3次重连的，就去重连
                                reconnectParamConnect(device, connectParam);
                            }
                        }else if (disConectTimes - reconnection <= 0) {
                            //除了倒数第一，第二次的，其他次数就作为重连
                            reconnectParamConnect(device, connectParam);
                        }
                    }
                }

            }else{
                //没有用配置参数方式的断开
                BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress());
            }
        }else{
            //没有用配置参数方式的断开
            BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress());
        }
    }

    /**
     * 参数配置方式的重连
     * @param device
     * @param connectParam
     */
    private void reconnectParamConnect(BluetoothDevice device,BleConnectParam connectParam){
        long searchTime = connectParam.getReconnectSearchTime();
        BleLOG.i(tag,"第 " + connectParam.getDisConnectTimes() + " 次断开重连,重连次数 = " + connectParam.getReconnection());
        if(searchTime == 0){
            //是否触发搜索一次
            if(mConnectParams.get(device).isOneTimesScan()){
                //触发一下搜索,空搜索
                BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
                BleDeviceScan.getInstance(BleConfig.mContext).scanDevice(1000, new IScanListener() {
                    @Override
                    public void OnScanning() {

                    }

                    @Override
                    public void OnScanEnd(int result) {

                    }

                    @Override
                    public void OnScanNewDevice(BluetoothDevice device, String name, int rssi, byte[] scanRecord) {

                    }
                },false);
                mConnectParams.get(device).setOneTimesScan(false);
                sendDelayeConnection(device.getAddress(),1300);
            }else{
                //不搜索,直接连接
                sendDelayeConnection(device.getAddress(),connectParam.getReconnectionIntervals());
            }
        }else if(searchTime > 0){
            //触发一下搜索,空搜索
            BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
            BleDeviceScan.getInstance(BleConfig.mContext).scanDevice(searchTime, new IScanListener() {
                @Override
                public void OnScanning() {

                }

                @Override
                public void OnScanEnd(int result) {

                }

                @Override
                public void OnScanNewDevice(BluetoothDevice deviceTmp, String name, int rssi, byte[] scanRecord) {
                    if(deviceTmp != null && device != null && device.getAddress().equals(deviceTmp.getAddress())){
                        BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
                        sendDelayeConnection(device.getAddress(),1000);
                    }
                }
            },false);
//            sendDelayeConnection(device.getAddress(),searchTime + 100);
        }else{
            BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
            BleDeviceScan.getInstance(BleConfig.mContext).scanDevice(24 * 60 * 60 * 60 * 1000, new IScanListener() {
                @Override
                public void OnScanning() {

                }

                @Override
                public void OnScanEnd(int result) {

                }

                @Override
                public void OnScanNewDevice(BluetoothDevice deviceTmp, String name, int rssi, byte[] scanRecord) {
                    if(deviceTmp != null && device != null && device.getAddress().equals(deviceTmp.getAddress())){
                        BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
                        sendDelayeConnection(device.getAddress(),1000);
                    }
                }
            },false);
        }
    }

    /**
     * 设置延时连接
     * @param address
     * @param timeOut
     */
    private void sendDelayeConnection(String address,long timeOut){
        Message msg = new Message();
        msg.what = CONNECTION_DELAYED;
        msg.obj = address;
        mHandler.removeMessages(CONNECTION_DELAYED,address);
        mHandler.sendMessageDelayed(msg,timeOut);
    }
    /**
     * 设置超时
     * @param address
     * @param timeOut
     */
    private void sendTimeOut(String address,long timeOut){
        Message msg = new Message();
        msg.what = CONNECTION_TIMEOUT;
        msg.obj = address;
        mHandler.removeMessages(CONNECTION_TIMEOUT, address);
        mHandler.sendMessageDelayed(msg, timeOut);//开始倒计时，超时
    }
    /**
     * 移除超时
     * @param address
     */
    private void removeTimeOut(String address){
        BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
        mHandler.removeMessages(CONNECTION_TIMEOUT,address);//移除倒计时
    }

    /**
     * 移除连接
     * @param address
     */
    private void removeConnection(String address){
        BleDeviceScan.getInstance(BleConfig.mContext).stopScanDevice();
        mHandler.removeMessages(CONNECTION_DELAYED,address);
    }
    /**
     *
     */
    /**连接超时*/
    private static final int CONNECTION_TIMEOUT = 1001;
    //延时连接
    private static final int CONNECTION_DELAYED = 1002;

    protected class HandlerCallback implements Handler.Callback{

        @Override
        public boolean handleMessage(Message msg) {
            switch (msg.what){
                case CONNECTION_TIMEOUT: {
                    String address = (String) msg.obj;
                    BluetoothDevice device = getDevice(address);
                    BleLOG.e(tag, "connection time out " + address);
                    BleConnectParam connectParam = null;
                    removeTimeOut(address);//移除倒计时
                    if (mConnectParams.containsKey(device)) {
                        connectParam = mConnectParams.get(device);
                        if (connectParam != null) {
                            if(connectParam.isTimeOutDisconnected() || !isConnected(address)) {//如果超时需要断开的，这时才断开，
                                connectParam.setTimeOutDisconnect(true);//标志，超时断开的
                                removeConnection(address);
                                disconnect(address);//超时后不再重连了
                                //就不去重连了
                                BlePropertyObservable.getInstance().fireEvent(BleEventType.STATE_DISCONNECTED, device.getAddress(), connectParam);
                            }
                        }
                    }
                    BlePropertyObservable.getInstance().fireEvent(BleEventType.BLE_CONNECT_TIME_OUT, (String) msg.obj, connectParam);
                }
                break;
                case CONNECTION_DELAYED: {
                    String address = (String) msg.obj;
                    BluetoothDevice device = getDevice(address);
                    BleConnectParam connectParam = null;
                    if (mConnectParams.containsKey(device) && (connectParam = mConnectParams.get(device)) != null) {
                        connect(device,connectParam.isBondIngDiscoverServices());
                    }else{

                    }
                    connect(device);
                }
                break;
            }
            return false;
        }
    }
    ////////////////////////////////////////////////////////////////////////////////////////////
    //数据发送
    //
    //
    ///////////////////////////////////////////////////////////////////////////////////////////

    /**
     * 发送数据
     * @param address
     * @param value
     * @param serviceUUid
     * @param characteristicUuid
     * @param isResponse 是否带回应
     * @return
     */
    public boolean sendMessage(String address,byte[] value,UUID serviceUUid,UUID characteristicUuid,boolean isResponse){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if(manager != null){
            return manager.sendMessage(value,serviceUUid,characteristicUuid,isResponse);
        }
        return false;
    }

    /**
     * 以读的方式发送数据
     * @param address
     * @param value
     * @param serviceUUid
     * @param characteristicUuid
     * @param isResponse 是否带回应
     * @return
     */
    public boolean sendMessageRead(String address,byte[] value,UUID serviceUUid,UUID characteristicUuid,boolean isResponse){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if(manager != null){
            return manager.sendMessageRead(value,serviceUUid,characteristicUuid,isResponse);
        }
        return false;
    }

    /**
     * 判读指定设备是否存在相应的服务UUID
     * @param address 蓝牙地址
     * @param serviceUUid 服务UUID
     * @return boolean
     */
    public boolean isExistThisUUID(String address, UUID serviceUUid){
        BluetoothDevice device = getDevice(address);
        final MyBleManager manager = getBleManager(device);
        if (manager != null){
            return manager.isExistUUID(serviceUUid);
        } else {
            return false;
        }
    }
}
